#include "common.h"
#include "port_ctrl.h"
#include "elab_pin.h"
#include "bsp_pin.h"
#include "shell.h"
#include "app_reserve_day.h"
#include "app_task.h"
static elab_pin_driver_t led;
uint32_t port_opt = 0;
static elab_pin_driver_t port[PORT_MAX];
static elab_device_t* device[PORT_MAX];


static void port_regisetr(void)
{
    bsp_gpio_pin_init(&led, "led", "D.13");

    bsp_gpio_pin_init(&port[PORT0], "PORT0", "D.15");
    bsp_gpio_pin_init(&port[PORT1], "PORT1", "F.03");
    bsp_gpio_pin_init(&port[PORT2], "PORT2", "C.10");
    bsp_gpio_pin_init(&port[PORT3], "PORT3", "C.11");
    bsp_gpio_pin_init(&port[PORT4], "PORT4", "F.02");
    bsp_hc595_gpio_pin_init(&port[PORT5], "PORT5", "HC595.00");
    bsp_hc595_gpio_pin_init(&port[PORT6], "PORT6", "HC595.01");
    bsp_hc595_gpio_pin_init(&port[PORT7], "PORT7", "HC595.02");
    bsp_hc595_gpio_pin_init(&port[PORT8], "PORT8", "HC595.03");
    bsp_hc595_gpio_pin_init(&port[PORT9], "PORT9", "HC595.04");
    bsp_hc595_gpio_pin_init(&port[PORT10], "PORT10", "HC595.05");
    bsp_hc595_gpio_pin_init(&port[PORT11], "PORT11", "HC595.06");
    bsp_hc595_gpio_pin_init(&port[PORT12], "PORT12", "HC595.07");

    for(int i = 0; i < PORT_MAX; i++)
    {
        char port_name[7];
        snprintf(port_name, sizeof(port_name), "PORT%d", i);
        device[i] = device_find(port_name);
        elab_pin_set_mode(device[i], PIN_MODE_OUTPUT_PP);
        elab_pin_set_status(device[i], 0);
    }
}

INIT_EXPORT(port_regisetr, EXPORT_LEVEL_BSP);


static void str_tolower(char* str, signed length) {
	for (int i = 0; i < length; i++) {
		str[i] = tolower(str[i]);
	}
}

static void port_ctrl(int argc, char *argv[])
{
    int port = 0;
    int activity = 0;
    char l[7] = {0};
    char invalid = 0;
    int ret;
    if(TIME_REMAIN_STOP == get_reserved_days())
    {
        elog_warn("Reserved days equal zero, Please set reserved days");
        return;
    }
    // elog_info("%dparameter(s)", argc);
    //1.检测输入参数个数
    if(3 != argc)
    {
        goto err;
    }
    
    //2.检测端口信息
    if(strlen(argv[1]) > (sizeof(l) - 1))
    {
        goto err;
    }
    else
    {
        memcpy(l, argv[1], strlen(argv[1]));
        str_tolower(l, sizeof(l));
        ret = sscanf(argv[1], "port%d%1s", &port, &invalid);
        if(ret != 1)
        {
            goto err;
        }
        else
        {
            if(port >= PORT_MAX || port < 0)
            {
                goto err;
            }
        }
    }

    //3.检查控制命令
    if(strlen(argv[2]) > 3)
    {
        goto err;
    }
    else
    {
        memset(l, 0, sizeof(l));
        memcpy(l, argv[2], strlen(argv[2]));
        str_tolower(l, sizeof(l));
        if(0 == memcmp(l, "on", strlen("on")))
        {
            activity = 1;
        }
        else if(0 == memcmp(l, "off", strlen("off")))
        {
            activity = 0;
        }
        else
        {
            goto err;
        }
    }

    //4.端口控制
    elab_pin_set_status(device[port], activity);
    elog_info("The port%d is already %s", port, activity ? "on" : "off");

    //5.记录当前端口打开情况
    if(activity)
    {
        set_port_opt(get_port_opt() | (1 << port));
    }
    else
    {
        set_port_opt(get_port_opt() & (~(1 << port)));
    }
    //6.存储端口打开情况到flash
    flash_operation_t operation;
    operation.type = FLASH_PIN_MAP;
    operation.port = get_port_opt();
    flash_operation_notify(operation);

    return;

err:
    elog_error("Invalid input paramter, please input port[0,%d] on/off", PORT_MAX - 1);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, port_ctrl, port_ctrl,\
Usage: user control port\r\n\
port_ctrl <portx> <on/off>\r\n\
For example:\r\n\
port_ctrl port0 on -user open port 0.\r\n);

void port_operation(uint32_t port)
{
    for(int i = 0; i < PORT_MAX; i++)
    {
        uint8_t activity = false;
        if((port >> i) & 0x01)
        {
            activity = true;
        }
        elab_pin_set_status(device[i], activity);
    }
}

static void port_query(int argc, char *argv[])
{
    int port = 0;
    char l[7] = {0};
    char invalid = 0;
    int ret;
    // elog_info("%dparameter(s)", argc);
    //1.检测输入参数个数
    if(1 != argc && 2 != argc)
    {
        goto err;
    }
    
    //2.1 查询所有端口信息
    if(1 == argc)
    {
        elog_info("----------------user query all port info----------------")
        elog_info("port\t\tstatus\t\treserve");
        for(int i = 0; i < PORT_MAX; i++)
        {
            elog_info("port%d\t\t%s\t\t%s", i, 
                                elab_pin_get_status(device[i]) ? "on" : "off", 
                                "--");
        }
        return;
    }

    //2.2 查询特定端口信息,获取端口信息
    if(strlen(argv[1]) > (sizeof(l) - 1))
    {
        goto err;
    }
    else
    {
        memcpy(l, argv[1], strlen(argv[1]));
        str_tolower(l, sizeof(l));
        ret = sscanf(argv[1], "port%d%1s", &port, &invalid);
        if(ret != 1)
        {
            goto err;
        }
        else
        {
            if(port >= PORT_MAX || port < 0)
            {
                goto err;
            }
        }
    }
    elog_info("----------------user query specific port info----------------")
    elog_info("port\t\tstatus\t\treserve");
    elog_info("port%d\t\t%s\t\t%s", port, 
                            elab_pin_get_status(device[port]) ? "on" : "off", 
                            "--");
    return;

err:
    elog_error("Invalid input paramter");
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, port_query, port_query,\
Usage: get control port info\r\n\
port_query [portx]\r\n\
For example:\r\n\
port_query -user get all port info.\r\n\
port_query port0 -user get port 0 info.);


uint32_t get_port_opt(void)
{
    return port_opt;
}

void set_port_opt(uint32_t opt)
{
    port_opt = opt;
}



